package main

import (
	"database/sql"
	"fmt"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/pjebs/restgate"
	"github.com/unrolled/secure"
	"net/http"
)

// 测试证书生成工具：https://keymanager.org/#
// 中间件对应的包：github.com/unrolled/secure
func runHttpsServer() {
	r := gin.Default()
	r.Use(httpsHandler()) //https对应的中间件
	r.GET("/https_test", func(c *gin.Context) {
		fmt.Println(c.Request.Host)
		c.JSON(http.StatusOK, gin.H{
			"code":   http.StatusOK,
			"result": "测试成功",
		})
	})

	//静态安全认证
	//r.Use(authMiddlewareStatic())

	//动态安全认证（使用数据库）
	r.Use(authMiddlewareDatabase())

	r.GET("/auth1", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"code":   http.StatusOK,
			"result": "验证通过",
		})
	})

	//开启HTTPS服务
	path := "/home/rx/go/gin-demo/CA/"              //证书的路径
	r.RunTLS(":8080", path+"ca.crt", path+"ca.key") //开启HTTPS服务
}

func httpsHandler() gin.HandlerFunc {
	return func(context *gin.Context) {
		secureMiddle := secure.New(secure.Options{
			SSLRedirect: true, //只允许https请求
			//SSLHost:"" //http到https的重定向
			STSSeconds:           1536000, //Strict-Transport-Security header的时效:1年
			STSIncludeSubdomains: true,    //includeSubdomains will be appended to the Strict-Transport-Security header
			STSPreload:           true,    //STS Preload(预加载)
			FrameDeny:            true,    //X-Frame-Options 有三个值:DENY（表示该页面不允许在 frame 中展示，即便是在相同域名的页面中嵌套也不允许）、SAMEORIGIN、ALLOW-FROM uri
			ContentTypeNosniff:   true,    //禁用浏览器的类型猜测行为,防止基于 MIME 类型混淆的攻击
			BrowserXssFilter:     true,    //启用XSS保护,并在检查到XSS攻击时，停止渲染页面
			//IsDevelopment:true,  //开发模式
		})
		err := secureMiddle.Process(context.Writer, context.Request)
		// 如果不安全，终止.
		if err != nil {
			context.AbortWithStatusJSON(http.StatusBadRequest, "数据不安全")
			return
		}
		// 如果是重定向，终止
		if status := context.Writer.Status(); status > 300 && status < 399 {
			context.Abort()
			return
		}
		context.Next()
	}
}

// 静态安全认证
func authMiddlewareStatic() gin.HandlerFunc {
	return func(c *gin.Context) {
		gate := restgate.New("X-Auth-Key",
			"X-Auth-Secret",
			restgate.Static, //静态验证
			restgate.Config{
				Key:                []string{"admin", "zhangsan"},
				Secret:             []string{"admin_pwd", "123456"},
				HTTPSProtectionOff: false, //如果是http服务，则这里使用true
			})
		nextCalled := false
		nextAdapter := func(http.ResponseWriter, *http.Request) {
			nextCalled = true
			c.Next()
		}
		gate.ServeHTTP(c.Writer, c.Request, nextAdapter)
		if nextCalled == false {
			c.AbortWithStatus(401)
		}
	}
}

// 动态安全认证
func authMiddlewareDatabase() gin.HandlerFunc {
	return func(c *gin.Context) {
		gate := restgate.New("X-Auth-key",
			"X-Auth-Secret",
			restgate.Database,
			restgate.Config{
				DB:                 db,
				TableName:          "auth",             //数据表名
				Key:                []string{"key"},    //key对应的字段名
				Secret:             []string{"secret"}, //secret对应的字段名
				HTTPSProtectionOff: true,
			})
		nextCalled := false
		nextAdapter := func(http.ResponseWriter, *http.Request) {
			nextCalled = true
			c.Next()
		}
		gate.ServeHTTP(c.Writer, c.Request, nextAdapter)
		if nextCalled == false {
			c.AbortWithStatus(401)
		}
	}
}

var db *sql.DB

func init() {
	db, _ = SqlDB()
}
func SqlDB() (*sql.DB, error) {
	//==============数据库连接方式1：==============
	DB_TYPE := "mysql"
	DB_HOST := "localhost"
	DB_PORT := "3306"
	DB_USER := "root"
	DB_NAME := "gin_demo"
	DB_PASSWORD := "rx123456"
	openString := DB_USER + ":" + DB_PASSWORD + "@tcp(" + DB_HOST + ":" + DB_PORT + ")/" + DB_NAME
	db, err := sql.Open(DB_TYPE, openString)
	return db, err
	//==============数据库连接方式2：==============
	/*
		//parseTime:时间格式转换;
		// loc=Local解决数据库时间少8小时问题
		var err error
		db, err = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/api_secure?charset=utf8&parseTime=true&loc=Local")
		if err != nil {
			log.Fatal("数据库打开出现了问题：", err)
			return db, err
		}
		// 尝试与数据库建立连接（校验dsn是否正确）
		err = db.Ping()
		if err != nil {
			log.Fatal("数据库连接出现了问题：", err)
			return db, err
		}
		return db, err
	*/
}
